#include "../include/show_bmp.h"

//显示一张bmp图片，参数是图片名和偏移坐标
void show_bmp(const char *pathname, int offset_x, int offset_y)
{
    int fd_lcd = open("/dev/fb0", O_RDWR);
    if(fd_lcd < 0)
    {
        perror("open lcd failed");
        exit(EXIT_FAILURE);
    }

    int *addr = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);
    if(addr == NULL)
    {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    int fd_bmp = open(pathname, O_RDWR);
    if(fd_bmp < 0)
    {
        perror("open bmp failed");
        exit(EXIT_FAILURE);
    }

    //读取图片信息
    int bmp_width = 0;
    int bmp_height = 0;

    lseek(fd_bmp, 18, SEEK_SET);
    read(fd_bmp, &bmp_width, 4);
    read(fd_bmp, &bmp_height, 4);

    char buf[bmp_width * bmp_height * 3];
    memset(buf, 0, sizeof(buf));

    lseek(fd_bmp, 54, SEEK_SET);
    read(fd_bmp, buf, sizeof(buf));

    int x = 0, y = 0;
    for(y = 0; y < bmp_height; y ++)
    {
        for(x = 0; x < bmp_width; x ++)
        {
            *(addr + (bmp_height - 1 - y + offset_y) * 800 + x + offset_x) = (buf[(y * bmp_width + x) * 3 + 0]) | (buf[(y * bmp_width + x) * 3 + 1] << 8) | (buf[(y * bmp_width + x) * 3 + 2] << 16);
        }
    }

    //释放资源
    munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
    close(fd_lcd);
    close(fd_bmp);
}

void show_bmp_mid_to_side(const char *pathname, int offset_x, int offset_y)
{
    int fd_lcd = open("/dev/fb0", O_RDWR);
    if(fd_lcd < 0)
    {
        perror("open lcd failed");
        exit(EXIT_FAILURE);
    }

    int *addr = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);
    if(addr == NULL)
    {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    int fd_bmp = open(pathname, O_RDWR);
    if(fd_bmp < 0) 
    {
        perror("open bmp failed");
        exit(EXIT_FAILURE);
    }

    //读取图片信息
    int bmp_width = 0;
    int bmp_height = 0;

    lseek(fd_bmp, 18, SEEK_SET);
    read(fd_bmp, &bmp_width, 4);
    read(fd_bmp, &bmp_height, 4);

    char buf[bmp_width * bmp_height * 3];
    memset(buf, 0, sizeof(buf));

    lseek(fd_bmp, 54, SEEK_SET);
    read(fd_bmp, buf, sizeof(buf));

    // 从中间开始往两边显示
    int start_x = bmp_width / 2;
    int end_x = bmp_width / 2;
    int step = 1; // 每次扩展的步长

    while (start_x > 0 || end_x < bmp_width)
    {
        for (int y = 0; y < bmp_height; y++)
        {
            for (int x = start_x; x <= end_x; x++)
            {
                *(addr + (bmp_height - 1 - y + offset_y) * LCD_WIDTH + x + offset_x) =
                    (buf[(y * bmp_width + x) * 3 + 0]) |
                    (buf[(y * bmp_width + x) * 3 + 1] << 8) |
                    (buf[(y * bmp_width + x) * 3 + 2] << 16);
            }
        }

        // 逐步扩展显示区域
        if (start_x > 0)
            start_x -= step;
        if (end_x < bmp_width)
            end_x += step;

        // 等待一段时间，以便看到效果
        usleep(10000); // 10ms
    }

    //释放资源
    munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
    close(fd_lcd);
    close(fd_bmp);
}

void* show_bmp_side_to_mid(void *arg)
{
    pthread_detach(pthread_self());

    struct bmp_info bi = *(struct bmp_info *)arg;

    // 打开LCD设备
    int fd_lcd = open("/dev/fb0", O_RDWR);
    if (fd_lcd < 0)
    {
        perror("open lcd failed");
        exit(EXIT_FAILURE);
    }

    // 映射显存
    int *addr = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);
    if (addr == MAP_FAILED)
    {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    // 打开BMP文件
    int fd_bmp = open(bi.pathname, O_RDWR);
    if (fd_bmp < 0)
    {
        perror("open bmp failed");
        exit(EXIT_FAILURE);
    }

    // 读取图片信息
    int bmp_width = 0;
    int bmp_height = 0;

    lseek(fd_bmp, 18, SEEK_SET);
    read(fd_bmp, &bmp_width, 4);
    read(fd_bmp, &bmp_height, 4);

    // 检查图片是否超出屏幕范围
    if (bi.offset_x + bmp_width > LCD_WIDTH || bi.offset_y + bmp_height > LCD_HEIGHT)
    {
        printf("BMP image exceeds LCD boundaries\n");
        munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
        close(fd_lcd);
        close(fd_bmp);
        return NULL;
    }

    // 读取图片数据
    char buf[bmp_width * bmp_height * 3];
    memset(buf, 0, sizeof(buf));

    lseek(fd_bmp, 54, SEEK_SET);
    read(fd_bmp, buf, sizeof(buf));

    // 从两边往中间显示的动画效果
    int left = 0;
    int right = bmp_width - 1;
    int step = 2; // 每次收缩的步长，可以根据需要调整
    int mid_point = bmp_width / 2;

    while (left <= mid_point && right >= mid_point)
    {
        // 绘制左侧到当前left位置的像素
        for (int y = 0; y < bmp_height; y++)
        {
            for (int x = 0; x <= left; x++)
            {
                if (x > bmp_width - 1) 
                    continue;
                *(addr + (bmp_height - 1 - y + bi.offset_y) * LCD_WIDTH + x + bi.offset_x) =
                    (buf[(y * bmp_width + x) * 3 + 0]) |
                    (buf[(y * bmp_width + x) * 3 + 1] << 8) |
                    (buf[(y * bmp_width + x) * 3 + 2] << 16);
            }
        }

        // 绘制右侧到当前right位置的像素
        for (int y = 0; y < bmp_height; y++)
        {
            for (int x = right; x < bmp_width; x++)
            {
                if (x < 0) continue;
                *(addr + (bmp_height - 1 - y + bi.offset_y) * LCD_WIDTH + x + bi.offset_x) =
                    (buf[(y * bmp_width + x) * 3 + 0]) |
                    (buf[(y * bmp_width + x) * 3 + 1] << 8) |
                    (buf[(y * bmp_width + x) * 3 + 2] << 16);
            }
        }

        // 更新左右边界
        left += step;
        right -= step;

        // 确保更新后的边界不超过中间点
        if (left > mid_point) left = mid_point;
        if (right < mid_point) right = mid_point;

        if(left == right)
            break;

        // 等待一段时间，以便看到动画效果
        usleep(5000); // 1ms
    }

    // 释放资源
    munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
    close(fd_lcd);
    close(fd_bmp);
}

void show_bmp_side_to_mid1(const char *pathname, int offset_x, int offset_y)
{
    // 打开LCD设备
    int fd_lcd = open("/dev/fb0", O_RDWR);
    if (fd_lcd < 0)
    {
        perror("open lcd failed");
        exit(EXIT_FAILURE);
    }

    // 映射显存
    int *addr = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);
    if (addr == MAP_FAILED)
    {
        perror("mmap failed");
        exit(EXIT_FAILURE);
    }

    // 打开BMP文件
    int fd_bmp = open(pathname, O_RDWR);
    if (fd_bmp < 0)
    {
        perror("open bmp failed");
        exit(EXIT_FAILURE);
    }

    // 读取图片信息
    int bmp_width = 0;
    int bmp_height = 0;

    lseek(fd_bmp, 18, SEEK_SET);
    read(fd_bmp, &bmp_width, 4);
    read(fd_bmp, &bmp_height, 4);

    // 检查图片是否超出屏幕范围
    if (offset_x + bmp_width > LCD_WIDTH || offset_y + bmp_height > LCD_HEIGHT)
    {
        printf("BMP image exceeds LCD boundaries\n");
        munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
        close(fd_lcd);
        close(fd_bmp);
        return;
    }

    // 读取图片数据
    char buf[bmp_width * bmp_height * 3];
    memset(buf, 0, sizeof(buf));

    lseek(fd_bmp, 54, SEEK_SET);
    read(fd_bmp, buf, sizeof(buf));

    // 从两边往中间显示的动画效果
    int left = 0;
    int right = bmp_width - 1;
    int step = 2; // 每次收缩的步长，可以根据需要调整
    int mid_point = bmp_width / 2;

    while (left <= mid_point && right >= mid_point)
    {
        // 绘制左侧到当前left位置的像素
        for (int y = 0; y < bmp_height; y++)
        {
            for (int x = 0; x <= left; x++)
            {
                if (x > bmp_width - 1) 
                    continue;
                *(addr + (bmp_height - 1 - y + offset_y) * LCD_WIDTH + x + offset_x) =
                    (buf[(y * bmp_width + x) * 3 + 0]) |
                    (buf[(y * bmp_width + x) * 3 + 1] << 8) |
                    (buf[(y * bmp_width + x) * 3 + 2] << 16);
            }
        }

        // 绘制右侧到当前right位置的像素
        for (int y = 0; y < bmp_height; y++)
        {
            for (int x = right; x < bmp_width; x++)
            {
                if (x < 0) continue;
                *(addr + (bmp_height - 1 - y + offset_y) * LCD_WIDTH + x + offset_x) =
                    (buf[(y * bmp_width + x) * 3 + 0]) |
                    (buf[(y * bmp_width + x) * 3 + 1] << 8) |
                    (buf[(y * bmp_width + x) * 3 + 2] << 16);
            }
        }

        // 更新左右边界
        left += step;
        right -= step;

        // 确保更新后的边界不超过中间点
        if (left > mid_point) left = mid_point;
        if (right < mid_point) right = mid_point;

        if(left == right)
            break;

        // 等待一段时间，以便看到动画效果
        usleep(5000); // 1ms
    }

    // 释放资源
    munmap(addr, LCD_WIDTH * LCD_HEIGHT * 4);
    close(fd_lcd);
    close(fd_bmp);
}

